#ifndef __JSMI_H
#define __JSMI_H
#include "jsmn.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#define JSMI_PARSER_TOK_NUM_MIN    100
#define JSMI_PARSER_TOK_NUM_STEP   50
#define JSMI_PARSER_TOK_NUM_MAX    400

#ifdef __cplusplus
extern "C" {
#endif

/* --------------------------------------------------------------------- parser */
typedef jsmntok_t jsmitok_t;

typedef enum {
    JSMI_UNDEFINED = JSMN_UNDEFINED,
    JSMI_OBJECT    = JSMN_OBJECT,
    JSMI_ARRAY     = JSMN_ARRAY,
    JSMI_STRING    = JSMN_STRING,
    JSMI_PRIMITIVE = JSMN_PRIMITIVE
} jsmitype_t;

#define JSMI_TOKLEN(tok) ((tok)->end - (tok)->start)
#define JSMI_TOKTYPE(tok) (jsmitype_t)((tok)->type)
#define JSMI_TOKCHILDREN(tok) (tok)->size

typedef struct jsmi_parser* jsmi_parser_t;

struct jsmi_parser {
    const char *js;
    size_t js_len;
    jsmitok_t *tok_array;
    int tok_array_len;
    jsmn_parser jsmn_psr;
};

extern jsmi_parser_t jsmi_parser_create(const char *js, size_t js_len);
extern int jsmi_parser_delete(jsmi_parser_t parser);

/* parent == NULL, mean search in root layer */
extern const jsmitok_t* jsmi_key_value(jsmi_parser_t handle, const jsmitok_t *parent, const char *key);

/* can use JSMI_TOKCHILDREN to see how many items have */
extern const jsmitok_t* jsmi_array_value(jsmi_parser_t handle, const jsmitok_t *parent, size_t idx);

/*
 * return 0 ok.
 * key can be NULL for just convert value
 */
extern int jsmi_get_value_str(jsmi_parser_t handle, const jsmitok_t *parent, const char *key, char *str_buf, size_t buf_sz);
extern int jsmi_get_value_uint64(jsmi_parser_t handle, const jsmitok_t *parent, const char *key, uint64_t *value);
extern int jsmi_get_value_int64(jsmi_parser_t handle, const jsmitok_t *parent, const char *key, int64_t *value);
extern int jsmi_get_value_uint32(jsmi_parser_t handle, const jsmitok_t *parent, const char *key, uint32_t *value);
extern int jsmi_get_value_int32(jsmi_parser_t handle, const jsmitok_t *parent, const char *key, int32_t *value);
extern int jsmi_get_value_uint16(jsmi_parser_t handle, const jsmitok_t *parent, const char *key, uint16_t *value);
extern int jsmi_get_value_int16(jsmi_parser_t handle, const jsmitok_t *parent, const char *key, int16_t *value);
extern int jsmi_get_value_uint8(jsmi_parser_t handle,  const jsmitok_t *parent, const char *key, uint8_t *value);
extern int jsmi_get_value_int8(jsmi_parser_t handle,  const jsmitok_t *parent, const char *key, int8_t *value);
extern int jsmi_get_value_bool(jsmi_parser_t handle, const jsmitok_t *parent, const char *key, bool *value);
extern int jsmi_get_value_double(jsmi_parser_t handle,  const jsmitok_t *parent, const char *key, double *value);

/* --------------------------------------------------------------------- composer */
typedef struct jsmi_composer* jsmi_composer_t;

struct jsmi_composer {
    char *js;
    size_t js_size;
    size_t js_len;
};

extern jsmi_composer_t jsmi_composer_create(char *js, size_t js_size);
extern int jsmi_composer_delete(jsmi_composer_t composer);

extern int jsmi_set_object_begin(jsmi_composer_t composer);
extern int jsmi_set_object_end(jsmi_composer_t composer, bool has_more);
extern int jsmi_set_array_begin(jsmi_composer_t composer);
extern int jsmi_set_array_end(jsmi_composer_t composer, bool has_more);
extern int jsmi_set_comma(jsmi_composer_t composer);

/*
 * return 0 ok.
 * key can be NULL for just append value
 */
extern int jsmi_set_key(jsmi_composer_t composer, const char *key);
extern int jsmi_set_key_value_str(jsmi_composer_t composer, const char *key, const char* value, bool has_more);
extern int jsmi_set_key_value_uint64(jsmi_composer_t composer, const char *key, uint64_t value, bool has_more);
extern int jsmi_set_key_value_int64(jsmi_composer_t composer, const char *key, int64_t value, bool has_more);
extern int jsmi_set_key_value_uint32(jsmi_composer_t composer, const char *key, uint32_t value, bool has_more);
extern int jsmi_set_key_value_int32(jsmi_composer_t composer, const char *key, int32_t value, bool has_more);
extern int jsmi_set_key_value_uint16(jsmi_composer_t composer, const char *key, uint16_t value, bool has_more);
extern int jsmi_set_key_value_int16(jsmi_composer_t composer, const char *key, int16_t value, bool has_more);
extern int jsmi_set_key_value_uint8(jsmi_composer_t composer, const char *key, uint8_t value, bool has_more);
extern int jsmi_set_key_value_int8(jsmi_composer_t composer, const char *key, int8_t value, bool has_more);
extern int jsmi_set_key_value_bool(jsmi_composer_t composer, const char *key, bool value, bool has_more);
extern int jsmi_set_key_value_double(jsmi_composer_t composer, const char *key, double value, bool has_more);
extern int jsmi_set_sub_jsmi_str(jsmi_composer_t composer, const char* value, bool has_more);

#ifdef __cplusplus
}
#endif
#endif
